#pragma once

#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

// client端开一个子线程用来接收server处理任务后，返回回来的信息
#include <pthread.h>

namespace Client{
    using namespace std;

    class udpClient{
    public:
        udpClient(const string& serverip, const uint16_t& port)
            :_serverip(serverip), _serverport(port), _sockfd(-1), _quit(false){}

        void initClient(){
            // 1. 简历socket通信
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if(_sockfd == -1){
                cerr << "socket error: " << errno << strerror(errno) << endl;
                exit(2);
            }
            cout << "socket success: " << _sockfd << endl;
        }

        // 子线程结束信息
        static void *readerMessage(void* args){
            // 安全的类型转化
            int sockfd = *(static_cast<int*>(args));
            pthread_detach(pthread_self()); // 线程分离

            while(true){
                // recvfrom
                char buffer[1024];
                struct sockaddr_in server;
                socklen_t len = sizeof(server);
                size_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&server, &len);
                if(n >= 0) buffer[n] = 0;

                // 输出 server 端传递过来的信息
                cout << buffer << endl;
            }
        }

        ////////////////////////////////////////////////////////////////
        // demo1 字典雏形小demo
        // void run(){
        //     // 子线程需要client端主线程的_sockfd用来接收server端返回回来的信息
        //     pthread_create(&_reader, nullptr, readerMessage, (void*)&_sockfd);

        //     // sendto 信息
        //     struct sockaddr_in server;
        //     bzero(&server, sizeof(server));
        //     server.sin_family = AF_INET;
        //     server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        //     server.sin_port = htons(_serverport);

        //     string message;
        //     char buffer[1024];
        //     while(true){
        //         cout << "Enter# ";
        //         fflush(stdout);

                   // 输入要发查找的单词
        //         fgets(buffer, sizeof(buffer) - 1, stdin);
        //         buffer[strlen(buffer) - 1] = 0;
        //         message = buffer;
        //         sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof(server));
        //     }
        // }

        ////////////////////////////////////////////////////////////////
        // demo2 让server执行一些指令
        // void run(){
        //    // 子线程需要client端主线程的_sockfd用来接收server端返回回来的信息
        //     pthread_create(&_reader, nullptr, readerMessage, (void*)&_sockfd);

        //     // sendto 信息
        //     struct sockaddr_in server;
        //     bzero(&server, sizeof(server));
        //     server.sin_family = AF_INET;
        //     server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        //     server.sin_port = htons(_serverport);

        //     string message;
        //     char cmdline[1024];
        //     while(true){
        //         // cout << "Enter# ";
        //         fprintf(stderr, "Enter# ");
        //         fflush(stderr);
        //         fgets(cmdline, sizeof(cmdline) - 1, stdin);
        //         cmdline[strlen(cmdline) - 1] = 0;
        //         message = cmdline;
        //         sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof(server));
        //     }
        // }

        ////////////////////////////////////////////////////////////////
        // demo3 聊天室小雏形
        void run(){
            // 子线程需要client端主线程的_sockfd用来接收server端返回回来的信息
            pthread_create(&_reader, nullptr, readerMessage, (void*)&_sockfd);

            // sendto 信息
            struct sockaddr_in server;
            bzero(&server, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_serverport);
            server.sin_addr.s_addr = inet_addr(_serverip.c_str());

            string message;
            char buffer[1024];
            while(true){
                fprintf(stderr, "Enter# ");
                fflush(stderr);
                // 聊天的小伙伴输入要发送的信息
                fgets(buffer, sizeof(buffer) - 1, stdin);
                buffer[strlen(buffer) - 1] = 0;
                message = buffer;
                sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof(server));
            }
        }

        ~udpClient(){}

    private:
        int _sockfd;
        string _serverip;
        uint16_t _serverport;
        bool _quit;

        // client端主线程作为sendto信息给server的
        // 创建一个子线程作为recvfrom server发回来的信息的
        // 这里的线程间通信是通过 mkfifo fifo 创建的管道的通信的(子线程作为主线程的结果窗口)
        pthread_t _reader;
    };
}


